/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_httpd.htm
 *
 * Zhiqim Httpd is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.httpd.context;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.zhiqim.httpd.HttpSessionManager;
import org.zhiqim.httpd.context.config.ZAction;
import org.zhiqim.httpd.context.core.Action;
import org.zhiqim.httpd.context.core.Context;
import org.zhiqim.httpd.context.core.Interceptor;
import org.zhiqim.httpd.context.entity.UploadEntity;
import org.zhiqim.httpd.context.entity.ResourceEntity;
import org.zhiqim.httpd.websocket.HttpWebSocketManager;
import org.zhiqim.kernel.config.Group;
import org.zhiqim.kernel.logging.Log;
import org.zhiqim.kernel.logging.LogFactory;
import org.zhiqim.kernel.util.Arrays;
import org.zhiqim.kernel.util.Asserts;
import org.zhiqim.kernel.util.Classes;
import org.zhiqim.kernel.util.DateTimes;
import org.zhiqim.kernel.util.Validates;
import org.zhiqim.zml.ZmlEngine;
import org.zhiqim.zml.ZmlVariable;

/**
 * 实现ZML模式的上下文环境<br><br>
 * 1.继承自StaticContext类，实现ZML的上下文环境功能<br>
 * 2.支持配置目录过滤/conf/*和/zml/*和/ztmpl/*.zml,/ztmpl/*.htm目录下不允许访问<br>
 * 3.加载/conf/context.xml为上下文配置<br>
 *   3.1 Attribute为context属性配置<br>
 *   3.2 Interceptor为context的拦截器<br>
 *   3.3 Rule为在html中定义权限配置<br>
 *   3.4 Action为每path处理<br>
 * 4.加载/conf/context.zsml为配置ZML<br>
 * 
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 */
public class ZmlContext extends StaticContext implements Context
{
    private static final Log log = LogFactory.getLog(ZmlContext.class);
    
    private ZmlConfig config;                       //配置管理
    private HttpSessionManager sessionManager;      //会话管理器
    private ZmlEngine engine;                       //ZML引擎
    private ServiceExecutor serviceExecutor;        //服务处理器
    private ZmlWebSocketManager websocketManager;   //WS管理器
    
    public ZmlContext()
    {
        super();
        addFilter(ZC_FILTER_CONF_FILE);
        addFilter(ZC_FILTER_ZVIEW_FILE);
        addFilter(ZC_FILTER_ZTMPL_HTM);
        addFilter(ZC_FILTER_ZTMPL_ZML);
    }
    
    /** 创建ZML上下文环境 */
    public boolean create(Group group) throws Exception
    {        
        if (!super.create(group))
        {//初始化父类静态信息失败
            return false;
        }
        
        if (!initConfig(group))
        {//初始化本类信息失败
            return false;
        }
        
        if (!initZmlEngine())
        {// 初始化ZML引擎失败
            return false;
        }
        
        if (!initContext())
        {//初始化上下文配置信息失败
            return false;
        }
        
        return true;
    }
    
    /** 初始化配置信息 */
    public boolean initConfig(Group group)
    {
        //1.资源配置
        this.config = new ZmlConfig(this, resource, group.isTrue(_ZML_PATH_EXACTPRIOR_, true));
        this.serviceExecutor = new ServiceExecutor(this);
        
        //2.设置服务处理器和缺省处理器
        super.addHandler(new ResourceEntity());
        super.addHandler(new UploadEntity());
        super.addHandler(serviceExecutor);
        super.setDefaultHandler(new ZmlExecutor(group.getString(_ZML_PATTERN_, _ZML_PATTERN_DEFAULT_)));
        
        //3.Cookie参数配置
        super.setCookieUse(group.isTrue(_ZML_COOKIE_USE_, true));
        super.setCookieDomain(group.getString(_ZML_COOKIE_DOMAIN_));
        super.setCookiePort(group.getInt(_ZML_COOKIE_PORT_, 0));
        super.setCookiePath(group.getString(_ZML_COOKIE_PATH_));
        super.setCookieForce(group.isTrue(_ZML_COOKIE_FORCE_, false));
        super.setEncodeable(group.isTrue(_ZML_ISENCODEABLE_, false));
        
        //4.Session管理器配置
        String sessionManager = group.getString(_ZML_SESSION_MANAGER_, _HTTP_SESSION_MANAGER_DEFAULT_);
        Object manager = Classes.newInstance(sessionManager);
        Asserts.as((manager instanceof HttpSessionManager)?null:"未找到["+group.getId()+"]的["+_ZML_SESSION_MANAGER_+"]或不是HttpSessionManager实现类");
        
        HttpSessionManager httpSessionManager = (HttpSessionManager)manager;
        httpSessionManager.setContext(this);
        httpSessionManager.setSessionTimeout(group.getInt(_ZML_SESSION_TIMEOUT_, 1800));
        httpSessionManager.setSessionIdName(group.getString(_ZML_SESSION_ID_NAME_, _JSESSIONID_));
        httpSessionManager.setSessionIdMark(group.getString(_ZML_SESSION_ID_MARK_));
        httpSessionManager.setSessionMust(group.getString(_ZML_SESSION_MUST_));
        httpSessionManager.setSessionNot(group.getString(_ZML_SESSION_NOT_));
        httpSessionManager.setSessionParameter(group.getString(_ZML_SESSION_PARAMETER_, _EMPTY_));
        httpSessionManager.open();
        this.sessionManager = httpSessionManager;
        
        //5.Websocket管理器配置
        this.websocketManager = new ZmlWebSocketManager(this);
        this.websocketManager.open();
        return true;
    }
    
    /**
     * 初始化ZML引擎
     * 
     * @throws Exception
     */
    private boolean initZmlEngine()
    {
        String resourcePath = getResourcePath();
        if (Validates.isEmptyBlank(resourcePath))
        {//仅RMI服务，未配置资源目录的不初始化ZML引擎
            return true;
        }
        
        log.info("初始化[HTTP服务:%s][ZML引擎]开始...[%s]", getServerId(), DateTimes.getDateTimeSSSString());
        
        try
        {
            engine = new ZmlEngine();
            engine.setZmlVarNotice(config);
            engine.setAscQuery(false);
            engine.setMaxKeepTime(getAttributeInt(_ZML_MAX_KEEP_TIME_, 24*60*60));//24小时
            engine.setMaxIdleTime(getAttributeInt(_ZML_MAX_IDLE_TIME_, 1*60*60));//1小时
            if (isClasspath())
                engine.setClassZmlLoader(ZmlContext.class, resourcePath);
            else
                engine.setFileZmlLoader(new File(resourcePath));

            log.info("初始化[HTTP服务:%s][ZML引擎]结束!!![%s]", getServerId(), DateTimes.getDateTimeSSSString());
            return true;
        }
        catch (Exception e)
        {
            log.error("初始化[ZML引擎]错误", e);
            return false;
        }
    }
    
    /** 初始化配置信息 */
    private boolean initContext()
    {
        log.info("初始化[HTTP服务:%s][Context:%s]开始...[%s]", getServerId(), getContextName(), DateTimes.getDateTimeSSSString());
        
        try
        {
            if (!config.create())
                return false;
            
            log.info("初始化[HTTP服务:%s][Context:%s]完成!!![%s]", getServerId(), getContextName(), DateTimes.getDateTimeSSSString());
            return true;
        }
        catch(Exception e)
        {
            log.error("初始化[HTTP服务:%s][Context:%s]失败!!!" , e, getServerId(), getContextName());
            return false;
        }
    }
    
    @Override /** 销毁ZML上下文环境 */
    public void destroy()
    {
        if (!isRunning)
            return;
        
        //销毁父类中的数据
        super.destroy();
        
        if (config != null)
        {//销毁配置
            config.destroy();
        }
        
        if (sessionManager != null)
        {//关闭会话管理
            sessionManager.close();
        }
        
        if (websocketManager != null)
        {//关闭WS管理器
            websocketManager.close();
        }
    }
    
    /** 重写判断是否有属性 */
    public boolean hasAttribute(String key)
    {
        return config.has(key);
    }
    
    /** 重写获取属性 */
    public Object getAttribute(String key)
    {
        return ZmlVariable.chkDynamicVar(config.get(key));
    }
    
    /** 判断是否有HTTP属性 */
    public boolean hasTopAttribute(String key)
    {
        return attributes.containsKey(key);
    }
    
    /** 获取顶有属性对象 */
    public Object getTopAttribute(String key)
    {
        return attributes.get(key);
    }
    
    /** 获取顶有属性字符串 */
    public String getTopAttributeString(String key)
    {
        return (String)attributes.get(key);
    }
    
    /** 获取顶有属性字符串，有属性则返回字符串，否则返回缺省值 */
    public String getTopAttributeString(String key, String defaultValue)
    {
        return hasTopAttribute(key)?getTopAttributeString(key):defaultValue;
    }
    
    /************************************************************************/
    //Bootstrap & RMIServer & Zml
    /************************************************************************/
    
    @Override
    public String getServerId()
    {
        return getServer().getId();
    }
    
    @Override
    public ZmlConfig getConfig()
    {
        return config;
    }
    
    @Override
    public ZmlBootstrap getBootstrap()
    {
        return config.getBootstrap();
    }
    
    @Override
    public ServiceExecutor getServiceExecutor()
    {
        return serviceExecutor;
    }
    
    @Override
    public ZmlEngine getZmlEngine()
    {
        return engine;
    }
    
    /************************************************************************/
    // session
    /************************************************************************/
    
    @Override
    public HttpSessionManager getSessionManager()
    {
        return sessionManager;
    }
    
    @Override
    public void invalidateSession(String sessionId)
    {
        if (sessionManager != null)
            sessionManager.invalidateSession(sessionId);
    }
    
    /************************************************************************/
    //Action & Interceptor
    /************************************************************************/
    
    @Override
    public ZAction getAction(String path)
    {
        return config.getAction(path);
    }
    
    @Override
    public Action getAction(ZAction fAction)
    {
        return config.getAction(fAction);
    }
    
    @Override
    public boolean hasActionInstance(String clazz)
    {
        return getActionInstance(clazz) != null;
    }
    
    @Override
    public Action getActionInstance(String clazz)
    {
        return config.getActionInstance(clazz);
    }
    
    @Override
    public boolean hasInterceptor(String interceptor)
    {
        return config.hasInterceptor(interceptor);
    }
    
    @Override
    public Interceptor getInterceptor(String interceptor)
    {
        return config.getInterceptor(interceptor);
    }
    
    @Override
    public List<Interceptor> getInterceptorList(String interceptors)
    {
        if (Validates.isEmpty(interceptors))
            return new ArrayList<Interceptor>(0);
        
        List<Interceptor> interceptorList = new ArrayList<Interceptor>();
        
        String[] interceptorArr = Arrays.toStringArray(interceptors);
        for (String interceptor : interceptorArr)
        {
            Interceptor ic = getInterceptor(interceptor);
            if (ic != null)
                interceptorList.add(ic);
        }
        
        return interceptorList;
    }
    
    @Override
    public HttpWebSocketManager getWebSocketManager()
    {
        return websocketManager;
    }
}
